package name.luojun.DBhelper;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Map.Entry;
import name.luojun.DBhelper.iface.DriverSupport;
import name.luojun.DBhelper.model.PrimaryKey;
import name.luojun.DBhelper.model.SimpleColumn;
import name.luojun.DBhelper.model.SimpleTable;
import name.luojun.DBhelper.utils.MysqlDriver;
import name.luojun.DBhelper.utils.OracleDriver;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcDaoSupport;
public class SimpleTableManager extends NamedParameterJdbcDaoSupport {
	private Logger log = Logger.getLogger(SimpleTableManager.class);
	private String configPath[];
	private String dialect = "oracle";
	private DriverSupport driver;
	private SAXReader saxreader = new SAXReader();
	public String[] getConfigPath() {
		return configPath;
	}
	public void setConfigPath(String[] configPath) {
		this.configPath = configPath;
	}
	public String getDialect() {
		return dialect;
	}
	public void setDialect(String dialect) {
		this.dialect = dialect;
	}
	@Override
	protected void checkDaoConfig() {
		super.checkDaoConfig();
		ResourcePatternResolver resourceLoader = new PathMatchingResourcePatternResolver();
		Connection connection = this.getConnection();
		if (dialect.equalsIgnoreCase("ORACLE")) {
			driver = new OracleDriver(connection);
		} else if(dialect.equalsIgnoreCase("Mysql")){
			driver = new MysqlDriver(connection);
		}else {
			this.releaseConnection(connection);
			throw new RuntimeException("Dialect not support!");
		}
		try {
			for (String path : configPath) {
				Resource[] source = resourceLoader.getResources(path);
				for (Resource r : source) {
					updateSchema(r);
				}
			}
		} catch (Exception e) {
			this.releaseConnection(driver.releaseConnection());
			throw new RuntimeException(e);
		}
		this.releaseConnection(driver.releaseConnection());
	}
	@SuppressWarnings("unchecked")
	private void updateSchema(Resource source) throws DocumentException, IOException {
		Document document = saxreader.read(source.getInputStream());
		Element root = document.getRootElement();
		List<Element> elements = root.elements("table");
		for (Element e : elements) {
			SimpleTable table = parse(e);
			updateTable(table);
		}
	}
	private void updateTable(SimpleTable table) {
		try {
			SimpleTable before = driver.getTable(table.getName(), "%");
			if (before.getColumns().size() == 0) {
				driver.createTable(table);
				driver.addPrimayKey(table);
				for (Entry<String, SimpleColumn> en : table.getColumns().entrySet()) {
					driver.addcomment(table, en.getValue());
				}
			} else {
				for (Entry<String, SimpleColumn> en : table.getColumns().entrySet()) {
					SimpleColumn columnbefore = before.getColumn(en.getKey());
					if (columnbefore == null) {
						driver.addColumn(table, en.getValue());
					} else if (!en.getValue().equals(columnbefore)) {
						driver.modifyColumn(table, en.getValue(), columnbefore);
					}
				}
				if (table.getPrimarykey() != null && !table.getPrimarykey().equals(before.getPrimarykey())) {
					if (before.getPrimarykey() != null)
						driver.dropPrimayKey(before);
					driver.addPrimayKey(table);
				}
			}
		} catch (Exception e) {
			log.error(e.getMessage());
		}
	}
	@SuppressWarnings("unchecked")
	private SimpleTable parse(Element e) {
		SimpleTable table = new SimpleTable();
		Element pk = e.element("primarykey");
		String tab = e.attributeValue("name");
		table.setName(tab.toUpperCase());
		List<Element> pkcs = e.elements("column");
		for (Element col : pkcs) {
			SimpleColumn column = this.getColumn(col);
			table.setColumn(column);
		}
		if (pk != null) {
			PrimaryKey primaryKey = new PrimaryKey();
			String pkname = pk.attributeValue("name");
			if (pkname != null)
				primaryKey.setName(pkname.toUpperCase());
			String columns[] = pk.attributeValue("column").split(",");
			for (String colname : columns) {
				primaryKey.addColumn(colname.trim().toUpperCase());
			}
			table.setPrimarykey(primaryKey);
		}
		return table;
	}
	public SimpleTable getTableFromDB(String name) {
		SimpleTable result = null;
		Connection conn = this.getConnection();
		driver.setConnection(conn);
		try {
			result = driver.getTable(name.toUpperCase(), "%");
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			this.releaseConnection(driver.releaseConnection());
		}
		return result;
	}
	private SimpleColumn getColumn(Element col) {
		String name = col.attributeValue("name").toUpperCase();
		String type = col.attributeValue("type").toUpperCase();
		String len = col.attributeValue("length");
		int length = 0;
		if (len != null && len.trim().length() > 0) {
			length = Integer.parseInt(len);
		}
		String notnull = col.attributeValue("not-null");
		String defaultvalue = col.attributeValue("default");
		String comment = col.attributeValue("comment");
		return new SimpleColumn(name, type, length, "true".equalsIgnoreCase(notnull), defaultvalue, comment);
	}
	public static String tableToXml(SimpleTable table) {
		StringBuffer result = new StringBuffer();
		result.append("<table name=\"" + table.getName() + "\" >\r\n");
		for (Entry<String, SimpleColumn> en : table.getColumns().entrySet()) {
			String col = columnToXml(en.getValue());
			result.append(col);
		}
		if (table.getPrimarykey() != null && table.getPrimarykey().getColumns().size() > 0) {
			result.append("<primarykey ");
			if (table.getPrimarykey().getName() != null) {
				result.append("name=\"" + table.getPrimarykey().getName() + "\" ");
			}
			result.append("column=\"");
			for (String str : table.getPrimarykey().getColumns()) {
				result.append(str + ",");
			}
			result.deleteCharAt(result.length() - 1);
			result.append("\" />\r\n");
		}
		result.append("</table>");
		return result.toString();
	}
	public static String columnToXml(SimpleColumn column) {
		StringBuffer result = new StringBuffer();
		result.append("<column ");
		if (column.getName() != null) {
			result.append("name=\"" + column.getName() + "\" ");
		}
		if (column.getType() != null) {
			result.append("type=\"" + column.getType() + "\" ");
		}
		if (column.getLength() != 0) {
			result.append("length=\"" + column.getLength() + "\" ");
		}
		if (column.getNotnull()) {
			result.append("not-null=\"true\" ");
		} else {
			result.append("not-null=\"false\" ");
		}
		if (column.getDefaultvalue() != null) {
			result.append("default=\"" + column.getDefaultvalue() + "\" ");
		}
		if (column.getComment() != null)
			result.append("comment=\"" + column.getComment() + "\" ");
		result.append("/>\r\n");
		return result.toString();
	}
}
